#define _XOPEN_SOURCE 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "traitement.h"
#include "config/config.h"
#include "real_path.h"

#define HTTP10 "HTTP/1.0"
#define HTTP11 "HTTP/1.1"

#define ACCEPT_ENCODING "Accept-Encoding" 
#define AUTHORIZATION   "Authorization"
#define CONTENT_LENGTH  "Content-Length"
#define USER_AGENT      "User-Agent"

requete_t
creer_requete()
{
  
  requete_t self=malloc(sizeof(struct requete_t));
 
  self->methode=pas_methode;
  self->protocole=pas_protocole;
  self->Accept_Encoding = NULL;
  self->Authorization   = NULL;
  self->Content_Length  = NULL;
  self->User_Agent      = NULL;
  self->url             = NULL;
  self->url_demande     = NULL;
  return self;
}



void
liberer_requete(requete_t self)
{
  if (self->Accept_Encoding != NULL)
    {
      free(self->Accept_Encoding);
      self->Accept_Encoding = NULL;
    }

  if (self->Authorization != NULL)
    {
      free(self->Authorization);
      self->Authorization = NULL;
    }
  if (self->Content_Length != NULL)
    {
      free(self->Content_Length);
      self->Content_Length = NULL;
    }
  if (self->User_Agent != NULL)
    {
      free(self->User_Agent);
      self->User_Agent = NULL;
    }
  if (self->url != NULL)
    {
      free(self->url);
      self->url = NULL;
    }

  if (self->url_demande !=NULL)
    {
      free(self->url_demande);
      self->url_demande = NULL;
    }
  
  free(self);
  self = NULL;
}

char*
recuperer_opt_aux(char *debut_ligne,char *option_cherchee)
{
  char *contenu_option = NULL;

  int i = strlen(option_cherchee) + 2; 
  int j = i;
  for (; debut_ligne[j] != '\n'&& debut_ligne[j] != '\r' && debut_ligne[j] != '\0';j++)
    ;
  int taille = j - i;
  
  if (taille <=0)
    return NULL;

  contenu_option = malloc(sizeof(char)*(taille+1));
  strncpy(contenu_option, debut_ligne+i, taille);
  contenu_option[taille] = '\0';

  return contenu_option;
}


void
recuperer_options(char *options,requete_t req)
{
  
  char *user = strstr(options,USER_AGENT);
  if (user != NULL)
    {
      req->User_Agent = recuperer_opt_aux(user,USER_AGENT);
    }


  char *auth = strstr(options,AUTHORIZATION);
  if (auth != NULL)
    {
      req->Authorization = recuperer_opt_aux(auth,AUTHORIZATION);
    }
  
  char *encoding = strstr(options,ACCEPT_ENCODING);
  if (encoding != NULL)
     {
       req->Accept_Encoding = recuperer_opt_aux(encoding,ACCEPT_ENCODING);
     }

  char *clength = strstr(options,CONTENT_LENGTH);
  if (clength != NULL)
    {
      req->Content_Length = recuperer_opt_aux(clength,CONTENT_LENGTH);
    }
}


requete_t
traiter_requete(char *requete_recue)
{
  requete_t resultat = creer_requete();
  
  char methode[5];
  //----------------recuperation methode ---------//
  int i = 0;
  for (; i < 5 && requete_recue[i] != ' ' && requete_recue[i] != '\0';i++)//methode delete pas geree, les commandes 
    ;                                                               //depassent pas 4 carac (head, post, get)
    
  if (requete_recue[i] != ' ')
    return resultat;
  //mauvaise requete

  if (sscanf(requete_recue,"%s ",methode) != 1)
    return resultat; //probleme
 

  if (strcmp(methode,"GET") == 0)
    resultat->methode = get;
  else
    if (strcmp(methode,"HEAD") == 0)
      resultat->methode = head;
    else
      if (strcmp(methode,"POST") == 0)
	resultat->methode = post;
      else
	return resultat;
  ///----------------recuperation url----------------//
  i++;
  int j ;
  for (j = i; requete_recue[j]!= '\n' && 
	 requete_recue[j] != ' ' && 
	 requete_recue[j] != '\r' && 
	 requete_recue[j] != '\0' ; j++)
    ;
  int taille_url = j - i ;
  if (taille_url == 0)
    return resultat;

  resultat->url_demande = malloc(sizeof(char)*(taille_url +1));
  strncpy(resultat->url_demande,requete_recue+i,taille_url);
  resultat->url_demande[taille_url]='\0';
  
  char vrai_path[BUFFER_SIZE];
  strcpy(vrai_path,chemin_correct(resultat->url_demande));
  
  if (strlen(vrai_path) == 0)
    return resultat;

  resultat->url = malloc(sizeof(char) * (strlen(vrai_path) + 1));
  strncpy(resultat->url,vrai_path,strlen(vrai_path));
  resultat->url[strlen(vrai_path)] = '\0';
  
  /*char *vraipath = chemin_correct(url);
  if (vraipath == NULL)//chemin non trouve
    return resultat;
   
  resultat->url = malloc(sizeof(char)*(strlen(vraipath)+1));
  strcpy(resultat->url, vraipath);
  */  
  ///-------------recuperation protocole--------------//

   resultat->protocole = http0_9;//par defaut protocole 0.9

  if (requete_recue[j] == '\0' || requete_recue[j] == '\n') //protocole 09 utilise
    {
      return resultat;
    }

  for (i = j+1; requete_recue[i]!= '\n' && 
	 requete_recue[i] != ' ' && 
	 requete_recue[i] != '\r' && 
	 requete_recue[i] != '\0' ; i++)
    ; //recup taille du protocole
  int taille_protocole = i - (j + 1);

  if (taille_protocole == 0)
    return resultat;

  if (taille_protocole != strlen(HTTP10))
    {
      resultat->methode = pas_methode;
      return resultat;
    }

  char protocole_utilise[taille_protocole+1];
  strncpy(protocole_utilise,requete_recue+j+1,sizeof(char)*taille_protocole);
  protocole_utilise[taille_protocole]='\0';

  if (strcmp(protocole_utilise,HTTP10))
    resultat->protocole = http1_0;
  else
    if (strcmp(protocole_utilise,HTTP11))
      resultat->protocole = http1_1;
    else
      {
	resultat->methode = pas_methode;
	return resultat;
      }

  
  if (requete_recue+i != NULL || requete_recue[i] != '\0') 
    recuperer_options(requete_recue+i,resultat);
  
  return resultat;
}

  
int
protocole_09(char *premiere_ligne)
{//A PASSER DANS UN .H LA CHAINE DE CARACTERES §§
  return (strstr(premiere_ligne,HTTP10) == NULL &&
	  strstr(premiere_ligne,HTTP11) == NULL);

}

char *
recupere_requete(int fdsock)
{
  char  buffer[BUFFER_SIZE];
  int   nb_read;
  int   size_requete = BUFFER_SIZE;
  char *requete = malloc(sizeof(char)*size_requete);
  
  int off = 0;

  while ((nb_read = read(fdsock,buffer, BUFFER_SIZE - 1)) > 0)
    {
      
      if (size_requete < off + nb_read)
	{
	  size_requete <<= 1;
	  requete = realloc(requete,sizeof(char)*size_requete);
	}

      buffer[nb_read] = '\0';
      
      strcpy(requete + off, buffer);
      off += nb_read;

      if (strchr(requete,'\n') != NULL && protocole_09(requete))//on detecte si cest le protocole 0.9 
	                                                        //utilise en regardant la premiere ligne
	break;

      if (strlen(requete) > 2 &&
	  (requete[strlen(requete)-2] == '\n' || requete[strlen(requete)-2] == '\r') && 
	   requete[strlen(requete)-1] == '\n')  //pour reperer fin de requete
	{
	  
	  break;
	}    
    }

  if (nb_read == 0)
    return NULL;

  requete = realloc(requete,sizeof(char)*(strlen(requete)+1));
  return requete;
}
  


/*int
main(int argc, char *argv[])
{
   char buffer[4095];
  int r;
  
  while ((r = read(0,buffer,sizeof(buffer))) != 0)
    {
      char path[1024];
      int req = traiter_requete(buffer,path);
      
      printf("requete = %d\npath = %s\n",req,path);

      }
 
  return EXIT_SUCCESS;
}*/

